﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace PolePosition.v3.DesktopFactory
{
    public class MobileSetup
    {
        public static event EventHandler DownloadPrerequisiteFilesComplete;
        public static event EventHandler<DownloadFilesProgressChangedEventArgs> DownloadPrerequisiteFilesProgessChanged;

        public static event EventHandler DownloadApplicationFilesComplete;
        public static event EventHandler BuildApplicationDatabaseComplete;
        public static event EventHandler<DownloadFilesProgressChangedEventArgs> DownloadApplicationFilesProgessChanged;

        public static bool PrerequisiteFilesComplete { get; set; }
        public static List<string> PrerequisiteFileList { get; set; }
        public static List<string> ApplicationFileList { get; set; }

        /// <summary>
        /// Creates the necessary directory structure for the mobile portion of the application. used
        /// to store mobile databases and images for vendors
        /// </summary>
        public static void DoDirectorySetup()
        {
            DirectoryInfo _repositoryDirectory = new DirectoryInfo(Constants.K_RepositoryFolder);
            if (!_repositoryDirectory.Exists)
                _repositoryDirectory.Create();
           
            if (_repositoryDirectory.GetDirectories(Constants.ErrorFolderName + "*").Length == 0)
                _repositoryDirectory.CreateSubdirectory(Constants.ErrorFolderName);
            
            if (_repositoryDirectory.GetDirectories(Constants.InboxFolderName + "*").Length == 0)
                _repositoryDirectory.CreateSubdirectory(Constants.InboxFolderName);
            
            if (_repositoryDirectory.GetDirectories(Constants.SentFolderName + "*").Length == 0)
                _repositoryDirectory.CreateSubdirectory(Constants.SentFolderName);
            
            if (_repositoryDirectory.GetDirectories(Constants.ImageCacheFolderName + "*").Length == 0)
                _repositoryDirectory.CreateSubdirectory(Constants.ImageCacheFolderName);
            
            if (_repositoryDirectory.GetDirectories(Constants.OutboxFolderName + "*").Length == 0)
                _repositoryDirectory.CreateSubdirectory(Constants.OutboxFolderName);

            DirectoryInfo tmpDirectory;
            if (_repositoryDirectory.GetDirectories(Constants.TempFolderName + "*").Length == 0)
                tmpDirectory = _repositoryDirectory.CreateSubdirectory(Constants.TempFolderName);
            else
                tmpDirectory = _repositoryDirectory.GetDirectories(Constants.TempFolderName + "*")[0];

            if (tmpDirectory.GetDirectories(Constants.K_INSPECTIONFOLDERNAME + "*").Length == 0)
                tmpDirectory.CreateSubdirectory(Constants.K_INSPECTIONFOLDERNAME);

            if (tmpDirectory.GetDirectories(Constants.K_GPSFOLDERNAME + "*").Length == 0)
                tmpDirectory.CreateSubdirectory(Constants.K_GPSFOLDERNAME);

            DirectoryInfo tmdDistributionInspectionDirectories = new DirectoryInfo(Constants.TempFolderName + "\\" + Constants.K_DISTRIBUTIONINSPECTIONFOLDERNAME);
            if (!tmdDistributionInspectionDirectories.Exists)
                tmpDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONINSPECTIONFOLDERNAME);

            DirectoryInfo tmdDistributionGPSDirectories = new DirectoryInfo(Constants.TempFolderName + "\\" + Constants.K_DISTRIBUTIONGPSFOLDERNAME);
            if (!tmdDistributionGPSDirectories.Exists)
                tmpDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONGPSFOLDERNAME);

            DirectoryInfo tmdDistributionInspectionMeterDirectories = new DirectoryInfo(Constants.TempFolderName + "\\" + Constants.K_DISTRIBUTIONINSPECTIONMETERFOLDERNAME);
            if (!tmdDistributionInspectionMeterDirectories.Exists)
                tmpDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONINSPECTIONMETERFOLDERNAME);

            DirectoryInfo tmdDistributionGPSMeterDirectories = new DirectoryInfo(Constants.TempFolderName + "\\" + Constants.K_DISTRIBUTIONGPSMETERFOLDERNAME);
            if (!tmdDistributionGPSMeterDirectories.Exists)
                tmpDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONGPSMETERFOLDERNAME);

            DirectoryInfo _outboxDirectory = new DirectoryInfo(Constants.K_OUTBOXPATH);
            if (_outboxDirectory.GetDirectories(Constants.K_GPSFOLDERNAME + "*").Length == 0)
                _outboxDirectory.CreateSubdirectory(Constants.K_GPSFOLDERNAME);

            if (_outboxDirectory.GetDirectories(Constants.K_INSPECTIONFOLDERNAME + "*").Length == 0)
                _outboxDirectory.CreateSubdirectory(Constants.K_INSPECTIONFOLDERNAME);

            DirectoryInfo _distributionOutboxDirectory = new DirectoryInfo(Constants.K_DISTRIBUTIONINSPECTIONFOLDERNAME);
            if (!_distributionOutboxDirectory.Exists)
                _outboxDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONINSPECTIONFOLDERNAME);

            _distributionOutboxDirectory = new DirectoryInfo(Constants.K_DISTRIBUTIONGPSFOLDERNAME);
            if (!_distributionOutboxDirectory.Exists)
                _outboxDirectory.CreateSubdirectory(Constants.K_DISTRIBUTIONGPSFOLDERNAME);
        }

        public static void DownloadPrerequisiteFiles(List<string> files)
        {
            PrerequisiteFilesComplete = false;

            Downloader _Downloader;
            _Downloader = new Downloader();

            PrerequisiteFileList = new List<string>();
            foreach (string _Url in files)
            {
                PrerequisiteFileList.Add(_Downloader.GetLocalFilePath(_Url));
            }

            _Downloader.DownloadComplete += delegate(object sender, EventArgs e)
            {
                PrerequisiteFilesComplete = true;

                //bubble up event
                if (DownloadPrerequisiteFilesComplete != null)
                    DownloadPrerequisiteFilesComplete(sender, e);

                _Downloader.Dispose();
            };

            _Downloader.DownloadProgessChanges += delegate(object sender, DownloadFilesProgressChangedEventArgs e)
            {
                //bubble up event if necessary
                if (DownloadPrerequisiteFilesProgessChanged != null)
                    DownloadPrerequisiteFilesProgessChanged(sender, e);
            };

            _Downloader.Download(files);
        }

        public static void DownloadApplicationFiles(int projectType, int utilityId, string utilityName, int vendorId, string vendorName, int projectId, string projectName, int inspectorId, string inspectorName)
        {
            Downloader _Downloader;
            _Downloader = new Downloader();
            string _DatabaseFile = null;

            _Downloader.DownloadComplete += delegate(object sender, EventArgs e)
            {
                //bubble up event
                if (DownloadApplicationFilesComplete != null)
                    DownloadApplicationFilesComplete(sender, e);

                _Downloader.Dispose();
            };

            _Downloader.DownloadProgessChanges += delegate(object sender, DownloadFilesProgressChangedEventArgs e)
            {
                //bubble up event if necessary
                if (DownloadApplicationFilesProgessChanged != null)
                    DownloadApplicationFilesProgessChanged(sender, e);
            };

            List<DownloadFileAttributes> _Files;
            _Files = new List<DownloadFileAttributes>();
            DownloadFileAttributes _File;

            if (projectType == v3.Common.Constants.ProjectTypes.DistributionGpsVisit)
            {
                //db
                _DatabaseFile = ServiceProxy.VendorService.GetDistributionGPSDatabasePath(vendorId, vendorName, inspectorId, inspectorName);
                if (!string.IsNullOrEmpty(_DatabaseFile))
                {
                    _DatabaseFile = ParseDownloadDatabase(_DatabaseFile);

                    _File = new DownloadFileAttributes();
                    _File.Url = _DatabaseFile;
                    _File.LocalFileName = Constants.K_LOCALDATABASEDISTRIBUTION;
                    _Files.Add(_File);
                }

                if (BuildApplicationDatabaseComplete != null)
                    BuildApplicationDatabaseComplete(null, EventArgs.Empty);

                //installer
                _File = new DownloadFileAttributes();
                _File.Url = Constants.K_WEBAPPLICATIONDISTRIBUTIONMOBILE;
                _Files.Add(_File);
            }
            else if (projectType == v3.Common.Constants.ProjectTypes.DistributionInspection)
            {
                //db
                _DatabaseFile = ServiceProxy.VendorService.GetDistributionInspectionDatabasePath(vendorId, vendorName, inspectorId, inspectorName);
                if (!string.IsNullOrEmpty(_DatabaseFile))
                {
                    _DatabaseFile = ParseDownloadDatabase(_DatabaseFile);

                    _File = new DownloadFileAttributes();
                    _File.Url = _DatabaseFile;
                    _File.LocalFileName = Constants.K_LOCALDATABASEDISTRIBUTION;
                    _Files.Add(_File);
                }

                if (BuildApplicationDatabaseComplete != null)
                    BuildApplicationDatabaseComplete(null, EventArgs.Empty);

                //installer
                _File = new DownloadFileAttributes();
                _File.Url = Constants.K_WEBAPPLICATIONDISTRIBUTIONMOBILE;
                _Files.Add(_File);
            }
            else if (projectType == v3.Common.Constants.ProjectTypes.XmissionGpsVisit)
            {
                //db
                _DatabaseFile = ServiceProxy.VendorService.GetXmissionGPSDatabasePath(utilityId, utilityName, vendorId, vendorName, projectId, projectName, inspectorId, inspectorName);

                if (!string.IsNullOrEmpty(_DatabaseFile))
                {
                    _DatabaseFile = ParseDownloadDatabase(_DatabaseFile);

                    _File = new DownloadFileAttributes();
                    _File.Url = _DatabaseFile;
                    _File.LocalFileName = Constants.K_LOCALDATABASEGPS;
                    _Files.Add(_File);
                }

                if (BuildApplicationDatabaseComplete != null)
                    BuildApplicationDatabaseComplete(null, EventArgs.Empty);

                //installer
                _File = new DownloadFileAttributes();
                _File.Url = Constants.K_WEBAPPLICATIONMOBILE;
                _Files.Add(_File);
            }
            else if (projectType == v3.Common.Constants.ProjectTypes.XmissionInspection)
            {
                //TODO: need to figure out a better way to get application file list 

                //db
                _DatabaseFile = ServiceProxy.VendorService.GetXmissionInspectionDatabasePath(utilityId, utilityName, vendorId, vendorName, projectId, projectName, inspectorId, inspectorName);

                if (!string.IsNullOrEmpty(_DatabaseFile))
                {
                    _DatabaseFile = ParseDownloadDatabase(_DatabaseFile);

                    _File = new DownloadFileAttributes();
                    _File.Url = _DatabaseFile;
                    _File.LocalFileName = Constants.K_LOCALDATABASEINSPECTIONS;
                    _Files.Add(_File);
                }



                if (BuildApplicationDatabaseComplete != null)
                    BuildApplicationDatabaseComplete(null, EventArgs.Empty);

                //installer
                _File = new DownloadFileAttributes();
                _File.Url = Constants.K_WEBAPPLICATIONINSPECTIONMOBILE;
                _Files.Add(_File);
            }

            

            ApplicationFileList = new List<string>();
            foreach (DownloadFileAttributes _DownloadFile in _Files)
            {
                ApplicationFileList.Add(string.Format("{0}{1}", Constants.K_InboxPath, _DownloadFile.LocalFileName));

                //ApplicationFileList.Add(_Downloader.GetLocalFilePath(_Url));
            }

            _Downloader.Download(_Files);
        }

        private static string ParseDownloadDatabase(string sourceDatabase)
        {
            sourceDatabase = sourceDatabase.Replace(Constants.K_SERVERBASEFODLER, Constants.K_SERVERBASEURL);
            sourceDatabase = sourceDatabase.Replace("\\", "/");
            return sourceDatabase;
        }

        public static void DeployFiles(int projectType, string destinationFolder)
        {
            //prereq files first
            foreach (string _LocalFilePath in PrerequisiteFileList)
            {
                FileInfo _FileToCopy = new FileInfo(_LocalFilePath);
                if (_FileToCopy.Exists)
                {
                    _FileToCopy.CopyTo(destinationFolder + "\\" + _FileToCopy.Name, true);
                }
            }

            //now project specific files
            foreach (string _LocalFilePath in ApplicationFileList)
            {
                FileInfo _FileToCopy = new FileInfo(_LocalFilePath);
                if (_FileToCopy.Exists)
                {
                    _FileToCopy.CopyTo(destinationFolder + "\\" + _FileToCopy.Name, true);
                }
            }
        }

        private class DownloadFileAttributes
        {
            public string Url { get; set; }
            public string LocalFileName { get; set; }
        }

        private class Downloader: IDisposable
        {
            protected Stack<string> m_WebFiles = new Stack<string>();
            protected Stack<string> m_LocalFiles = new Stack<string>();

            public event EventHandler DownloadComplete;
            public event EventHandler<DownloadFilesProgressChangedEventArgs> DownloadProgessChanges;

            public int TotalFiles { get; set; }
            public int TotalFilesComplete { get; set; }
            public long TotalBytes { get; set; }
            public long TotalBytesComplete { get; set; }

            private long m_startBytes;

            private DownloadFile m_Downloader;
            private DownloadFile FileDownload
            {
                get
                {
                    if (m_Downloader == null)
                    {
                        m_Downloader = new DownloadFile();
                        m_Downloader.FinishDownloadFile += new EventHandler(Downloader_FinishDownload);
                        m_Downloader.ProgressChanged += new EventHandler<System.Net.DownloadProgressChangedEventArgs>(Downloader_ProgressChanged);
                    }

                    return m_Downloader;
                }
            }

            public Downloader()
            {
                TotalFiles = 0;
                TotalFilesComplete = 0;
                TotalBytes = 0;
                TotalBytesComplete = 0;
                m_startBytes = 0;
            }

            private long? GetFileSize(string url)
            {
                System.Net.WebRequest _Request = null;
                System.Net.WebResponse _Response = null;
                try
                {
                    _Request = System.Net.HttpWebRequest.Create(url);
                    _Request.Method = "HEAD";
                    _Request.Timeout = 5000;
                    _Response = _Request.GetResponse();

                    int _ContentLength;
                    if (int.TryParse(_Response.Headers.Get("Content-Length"), out _ContentLength))
                        return _ContentLength;
                    
                }
                catch
                {
                    // swallow the Exception in this case

                }
                finally
                {
                    if (_Response != null)
                        _Response.Close();

                     if (_Request != null)
                        _Request.Abort();
                
                }

                return null;
            }

            public void Download(List<string> files)
            {
                List<DownloadFileAttributes> _Files;
                _Files = new List<DownloadFileAttributes>();
                DownloadFileAttributes _File;
                foreach (string _Url in files)
                {
                    _File = new DownloadFileAttributes();
                    _File.Url = _Url;
                    _Files.Add(_File);
                }

                Download(_Files);
            }

            public void Download(List<DownloadFileAttributes> files)
            {
                long? _FileSize = null;
                foreach (DownloadFileAttributes _DownloadFile in files)
                {
                    string _LocalFilePath;
                    string _Url;
                    _Url = _DownloadFile.Url;

                    if (!string.IsNullOrEmpty(_DownloadFile.LocalFileName))
                        _LocalFilePath = string.Format("{0}{1}", Constants.K_InboxPath, _DownloadFile.LocalFileName);
                    else
                        _LocalFilePath = GetLocalFilePath(_Url);

                    //only pull those files that are not already copied locally 
                    if (File.Exists(_LocalFilePath))
                    {
                        //and ensure they are not zero bytes
                        FileInfo _FileInfo = new FileInfo(_LocalFilePath);
                        long _Size = _FileInfo.Length;

                        if (_Size != 0)
                            continue;
                    }

                    m_WebFiles.Push(_Url);
                    m_LocalFiles.Push(_LocalFilePath);

                    _FileSize = GetFileSize(_Url);

                    if (_FileSize.HasValue)
                        TotalBytes += _FileSize.Value;

                    TotalFiles++;
                }

                //no files to copy
                if (m_LocalFiles.Count == 0)
                {
                    //nothing to download so its complete
                    if (DownloadComplete != null)
                        DownloadComplete(this, EventArgs.Empty);

                    return;
                }

                StartDownload();
            }

            public string GetLocalFilePath(string url)
            {
                //split apart url to get file name from file list
                int _LastPostion = url.LastIndexOf(@"/") + 1;
                string _FileName = url.Substring(_LastPostion);

                string _LocalFilePath;
                _LocalFilePath = string.Format("{0}{1}", Constants.K_InboxPath, _FileName);

                return _LocalFilePath;
            }

            private void StartDownload()
            {
                m_startBytes = TotalBytesComplete;
                
                if (m_LocalFiles.Count > 0 && m_WebFiles.Count > 0)
                {
                    FileDownload.SetUrl(m_WebFiles.Pop());
                    FileDownload.SetFileDestination(m_LocalFiles.Pop());
                    FileDownload.StartDownload();
                }
                else
                {
                    TotalBytesComplete = TotalBytes;
                }
            }

            #region Events

            private void Downloader_FinishDownload(object sender, EventArgs e)
            {
                try
                {
                    TotalFilesComplete++;

                    if (TotalFilesComplete != TotalFiles)
                    {
                        StartDownload();
                    }
                    else
                    {
                        //dispose of web client
                        if (m_Downloader != null)
                        {
                            //unwire events
                            m_Downloader.FinishDownloadFile -= new EventHandler(Downloader_FinishDownload);
                            m_Downloader.ProgressChanged -= new EventHandler<System.Net.DownloadProgressChangedEventArgs>(Downloader_ProgressChanged);
                            m_Downloader.CancelDownload();
                        }

                        if (DownloadComplete != null)
                            DownloadComplete(sender, e);

                    }
                }
                catch (Exception ex)
                {
                    //RegisterError.SaveError(ex);
                }
            }
          
            private void Downloader_ProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e)
            {
                int _ProgressBytes = 0;
                int.TryParse(e.BytesReceived.ToString(), out _ProgressBytes);

                TotalBytesComplete = m_startBytes + _ProgressBytes;

                if (DownloadProgessChanges != null)
                {
                    
                    DownloadFilesProgressChangedEventArgs _Args;
                    _Args = new DownloadFilesProgressChangedEventArgs() 
                    { 
                        BytesReceived = TotalBytesComplete,
                        TotalBytesToReceive = TotalBytes,
                        FilesReceived = TotalFilesComplete,
                        TotalFilesToReceive = TotalFiles,
                    };

                    DownloadProgessChanges(sender, _Args);
                }
            }
            
            #endregion

            #region IDisposable Members

            public void Dispose()
            {
                if (m_Downloader == null)
                    return;

                m_Downloader.Dispose();
                m_Downloader = null;
            }

            #endregion
        }

        public class DownloadFilesProgressChangedEventArgs: EventArgs
        {
            public int FilesReceived { get; set; }
            public int TotalFilesToReceive { get; set; }

            public long BytesReceived { get; set; }
            public long TotalBytesToReceive { get; set; }
            public int ProgressPercentage
            {
                get
                {
                    if (TotalBytesToReceive == 0)
                        return 0;
                    else
                    {
                        double _Div = 0;
                        _Div = Convert.ToDouble(BytesReceived) / Convert.ToDouble(TotalBytesToReceive);

                        return Convert.ToInt32(_Div * 100.0000);
                    }
                }
            }
        }

    }
}
